// test/framework.rs

use std::collections::{HashMap, HashSet};
use std::ptr;

// Assuming these are defined elsewhere in your Rust project
extern "C" {
    fn int_equal(a: *const i32, b: *const i32) -> bool;
    fn pointer_equal(p1: *const u8, p2: *const u8) -> bool;
    fn string_equal(s1: *const u8, s2: *const u8) -> bool;
    fn int_hash(a: *const i32) -> usize;
    fn pointer_hash(p: *const u8) -> usize;
    fn string_hash(s: *const u8) -> usize;

    fn arraylist_new(capacity: usize) -> *mut ArrayList;
    fn arraylist_free(arraylist: *mut ArrayList);

    fn avl_tree_new(compare: unsafe extern "C" fn(*const u8, *const u8) -> i32) -> *mut AVLTree;
    fn avl_tree_free(avl_tree: *mut AVLTree);

    fn binary_heap_new(heap_type: BinaryHeapType, compare: unsafe extern "C" fn(*const u8, *const u8) -> i32) -> *mut BinaryHeap;
    fn binary_heap_free(heap: *mut BinaryHeap);

    fn binomial_heap_new(heap_type: BinomialHeapType, compare: unsafe extern "C" fn(*const u8, *const u8) -> i32) -> *mut BinomialHeap;
    fn binomial_heap_free(heap: *mut BinomialHeap);

    fn bloom_filter_new(size: usize, hash_func: unsafe extern "C" fn(*const u8) -> usize, num_hashes: usize) -> *mut BloomFilter;
    fn bloom_filter_free(filter: *mut BloomFilter);

    fn hash_table_new(hash_func: unsafe extern "C" fn(*const u8) -> usize, equal_func: unsafe extern "C" fn(*const u8, *const u8) -> bool) -> *mut HashTable;
    fn hash_table_free(hash_table: *mut HashTable);

    fn list_prepend(list: &mut *mut ListEntry, data: *const i32);
    fn list_free(list: *mut ListEntry);

    fn queue_new() -> *mut Queue;
    fn queue_free(queue: *mut Queue);

    fn set_new(hash_func: unsafe extern "C" fn(*const u8) -> usize, equal_func: unsafe extern "C" fn(*const u8, *const u8) -> bool) -> *mut Set;
    fn set_free(set: *mut Set);

    fn slist_prepend(list: &mut *mut SListEntry, data: *const i32);
    fn slist_free(list: *mut SListEntry);

    fn trie_new() -> *mut Trie;
    fn trie_free(trie: *mut Trie);

    fn run_tests(tests: &[unsafe extern "C" fn()]);
}

type UnitTestFunction = unsafe extern "C" fn();

static TESTS: [Option<UnitTestFunction>; 16] = [
    Some(test_compare_int),
    Some(test_compare_pointer),
    Some(test_compare_string),
    Some(test_hash_int),
    Some(test_hash_pointer),
    Some(test_hash_string),
    Some(test_arraylist),
    Some(test_avl_tree),
    Some(test_binary_heap),
    Some(test_binomial_heap),
    Some(test_bloom_filter),
    Some(test_hash_table),
    Some(test_list),
    Some(test_queue),
    Some(test_set),
    Some(test_slist),
    Some(test_trie),
];

unsafe extern "C" fn test_compare_int() {
    let a = 1;
    let b = 2;
    assert!(!int_equal(&a, &b));
}

unsafe extern "C" fn test_compare_pointer() {
    let a = 1;
    let b = 2;
    assert!(!pointer_equal(ptr::addr_of!(a) as *const u8, ptr::addr_of!(b) as *const u8));
}

unsafe extern "C" fn test_compare_string() {
    let s1 = b"hello\0";
    let s2 = b"world\0";
    assert!(!string_equal(s1.as_ptr(), s2.as_ptr()));
}

unsafe extern "C" fn test_hash_int() {
    let a = 1;
    int_hash(&a);
}

unsafe extern "C" fn test_hash_pointer() {
    let a = 1;
    pointer_hash(ptr::addr_of!(a) as *const u8);
}

unsafe extern "C" fn test_hash_string() {
    let s = b"hello\0";
    string_hash(s.as_ptr());
}

unsafe extern "C" fn test_arraylist() {
    let arraylist = arraylist_new(10);
    arraylist_free(arraylist);
}

unsafe extern "C" fn test_avl_tree() {
    let avl_tree = avl_tree_new(|_, _| 0);
    avl_tree_free(avl_tree);
}

unsafe extern "C" fn test_binary_heap() {
    let binary_heap = binary_heap_new(BinaryHeapType::Min, |_, _| 0);
    binary_heap_free(binary_heap);
}

unsafe extern "C" fn test_binomial_heap() {
    let binomial_heap = binomial_heap_new(BinaryHeapType::Min, |_, _| 0);
    binomial_heap_free(binomial_heap);
}

unsafe extern "C" fn test_bloom_filter() {
    let bloom_filter = bloom_filter_new(100, string_hash, 3);
    bloom_filter_free(bloom_filter);
}

unsafe extern "C" fn test_hash_table() {
    let hash_table = hash_table_new(string_hash, string_equal);
    hash_table_free(hash_table);
}

unsafe extern "C" fn test_list() {
    let mut list = ptr::null_mut();
    let a = 1;
    let b = 2;
    let c = 3;
    list_prepend(&mut list, &a);
    list_prepend(&mut list, &b);
    list_prepend(&mut list, &c);
    list_free(list);
}

unsafe extern "C" fn test_queue() {
    let queue = queue_new();
    queue_free(queue);
}

unsafe extern "C" fn test_set() {
    let set = set_new(string_hash, string_equal);
    set_free(set);
}

unsafe extern "C" fn test_slist() {
    let mut list = ptr::null_mut();
    let a = 1;
    let b = 2;
    let c = 3;
    slist_prepend(&mut list, &a);
    slist_prepend(&mut list, &b);
    slist_prepend(&mut list, &c);
    slist_free(list);
}

unsafe extern "C" fn test_trie() {
    let trie = trie_new();
    trie_free(trie);
}

fn main() {
    unsafe {
        run_tests(&TESTS.iter().map(|&test| test).collect::<Vec<_>>());
    }
}
